package com.bobo.netty.server.websocketchat;

import com.bobo.netty.common.ConstantsRedis;
import com.bobo.netty.common.bizEnum.ChatTypeEnum;
import com.bobo.netty.common.bizEnum.MessageStatusEnum;
import com.bobo.netty.common.bizEnum.MessageTypeEnum;
import com.bobo.netty.dto.ChatMessageDTO;
import com.bobo.netty.service.ChatMessageService;
import com.bobo.netty.utils.JsonUtils;
import com.bobo.netty.utils.RedisUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component
@ChannelHandler.Sharable
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    private Logger LOGGER = LoggerFactory.getLogger(TextWebSocketFrameHandler.class);
    @Resource
    private ChatMessageService chatMessageService;
    @Resource
    private RedisUtils redisUtils;
    @Resource
    private RedisProcess redisProcess;
    public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
        Channel incoming = ctx.channel();
        String incomingChannelId = incoming.id().asLongText();
        String text = msg.text();
        LOGGER.info("接受到的消息：" + text);
        ChatMessageDTO chatMessageDTO = JsonUtils.jsonToPojo(text, ChatMessageDTO.class);
        if (chatMessageDTO == null) {
            return;
        }
        if (MessageTypeEnum.BIND_MSG.getCode().equals(chatMessageDTO.getMessageType())) {
            //绑定用户、渠道关系
            redisUtils.add(ConstantsRedis.USER_CHANNEL_ID_PRE + incomingChannelId, chatMessageDTO.getSendUserId());
            redisUtils.add(ConstantsRedis.USER_CHANNEL_ID_PRE + chatMessageDTO.getSendUserId(), incomingChannelId);
            channels.writeAndFlush(new TextWebSocketFrame("欢迎 - " + redisProcess.getUserName(incoming) + " 加入群聊"));
            return;
        }
        if (ChatTypeEnum.SINGLE_CHAT.getCode().equals(chatMessageDTO.getChatType())) {
            if (StringUtils.isNotBlank(chatMessageDTO.getReceiveUserId())) {
                /**
                 * 发他人
                 */
                //获取接收人的通道ID
                String receiveUserChannelId = (String) redisUtils.getValueBykeys(ConstantsRedis.USER_CHANNEL_ID_PRE + chatMessageDTO.getReceiveUserId());
                if (StringUtils.isBlank(receiveUserChannelId)) {
                    LOGGER.info(String.format("处理离线消息,渠道ID=%s,用户ID%s,消息=%s", receiveUserChannelId, receiveUserChannelId, chatMessageDTO.getContent()));
                    chatMessageDTO.setMessageStatus(MessageStatusEnum.OFFLINE_MSG.getCode());
                } else {
                    LOGGER.info(String.format("处理在线消息,渠道ID=%s,用户ID%s,消息=%s", receiveUserChannelId, receiveUserChannelId, chatMessageDTO.getContent()));
                    chatMessageDTO.setMessageStatus(MessageStatusEnum.ONLINE_MSG.getCode());
                }
                //尝试发送
                for (Channel channel : channels) {
                    if (channel.id().asLongText().equalsIgnoreCase(receiveUserChannelId)) {
                        channel.writeAndFlush(new TextWebSocketFrame("[" + redisProcess.getUserName(chatMessageDTO.getSendUserId()) + "]" + chatMessageDTO.getContent()));
                    }
                }
            } else {
                //发自己
                chatMessageDTO.setReceiveUserId(chatMessageDTO.getSendUserId());
            }
            //消息保存入库
            chatMessageService.saveMsgSingle(chatMessageDTO);
            incoming.writeAndFlush(new TextWebSocketFrame("[我]" + chatMessageDTO.getContent()));
        } else {

        }
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        String channelId = incoming.id().asLongText();
//        chatService.addChannelConnectDevice(new DeviceMsDTO(channelId));
        LOGGER.info(channelId + "链接成功");
        // 广播
        channels.add(incoming);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        // 广播
        channels.writeAndFlush(new TextWebSocketFrame(redisProcess.getUserName(incoming) + " 已离开"));
        redisProcess.removeChannelId(incoming);
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        System.out.println("Client:" + redisProcess.getUserName(incoming) + "在线");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        System.out.println("Client:" + redisProcess.getUserName(incoming) + "掉线");
        redisProcess.removeChannelId(incoming);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        Channel incoming = ctx.channel();
        System.out.println("Client:" + redisProcess.getUserName(incoming) + "异常");
        redisProcess.removeChannelId(incoming);
        // 当出现异常就关闭连接
        cause.printStackTrace();
        ctx.close();
    }
}
